﻿using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Collections.Specialized;
using System.Diagnostics;
using System;
using System.Data.Services.Client;

namespace OData.Silverlight
{
    public partial class AstoriaCollection<TEntity> : ICollectionView, IPagedCollectionView, INotifyPropertyChanged where TEntity : class, new()
    {
        private IDataSource<TEntity> _dataSource;
        public AstoriaCollection(IDataSource<TEntity> dataSource)
        {
            _dataSource = dataSource;
            _dataSource.GetTotalCountCompleted += new EventHandler<CountEventArgs>(_dataSource_GetTotalCountCompleted);

        }

        void _dataSource_GetTotalCountCompleted(object sender, CountEventArgs e)
        {
            this.TotalItemCount = e.TotalCount;
        }
        #region ICollectionView Members

        private bool _CanFilter;
        public bool CanFilter
        {
            get { return _CanFilter; }
            protected set
            {
                _CanFilter = value;
                RaisePropertyChanged("CanFilter");
            }
        }
        private bool _CanGroup;
        public bool CanGroup
        {
            get { return _CanGroup; }
            protected set
            {
                _CanGroup = value;
                RaisePropertyChanged("CanGroup");
            }
        }
        private bool _CanSort = true;
        public bool CanSort
        {
            get { return _CanSort; }
            protected set
            {
                _CanSort = value;
                RaisePropertyChanged("CanSort");
            }
        }

        public bool Contains(object item)
        {
            return SourceList.Contains(item as TEntity);
        }

        public System.Globalization.CultureInfo Culture
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        private void RaiseCurrentChanged()
        {
            if (CurrentChanged != null)
            {
                CurrentChanged(this, new EventArgs());
            }
        }

        private void RaiseCurrentChanging()
        {
            if (CurrentChanging != null)
            {
                bool cannotCancelCurrentChanging = false;
                CurrentChanging(this, new CurrentChangingEventArgs(cannotCancelCurrentChanging));
            }
        }
        public event EventHandler CurrentChanged;

        public event CurrentChangingEventHandler CurrentChanging;


        private object _CurrentItem;
        public object CurrentItem
        {
            get { return _CurrentItem; }
            protected set
            {
                RaiseCurrentChanging();
                _CurrentItem = value;
                RaiseCurrentChanged();
                RaisePropertyChanged("CurrentItem");
            }
        }

        private int _CurrentPosition;
        public int CurrentPosition
        {
            get { return _CurrentPosition; }
            protected set
            {
                _CurrentPosition = value;
                RaisePropertyChanged("CurrentPosition");
            }
        }

        public IDisposable DeferRefresh()
        {
            return new DeferRefreshHelper() { OnDispose = EndDeferRefresh };
        }
        private void EndDeferRefresh()
        {
            _dataSource.Sort(SortDescriptions);
            this.PageIndex = 0;
        }
        public Predicate<object> Filter
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public System.Collections.ObjectModel.ObservableCollection<GroupDescription> GroupDescriptions
        {
            get { return null; }
        }

        public System.Collections.ObjectModel.ReadOnlyObservableCollection<object> Groups
        {
            get { return null; }
        }

        public bool IsCurrentAfterLast
        {
            get { return CurrentPosition > PageSize; }
        }

        public bool IsCurrentBeforeFirst
        {
            get { return CurrentPosition == 0; }
        }

        public bool IsEmpty
        {
            get { return SourceCollection != null; }
        }

        public bool MoveCurrentTo(object item)
        {
            CurrentItem = item;
            return item != null;
        }

        public bool MoveCurrentToFirst()
        {
            CurrentItem = SourceList.First();
            return SourceList != null && SourceList.Count > 0;
        }

        public bool MoveCurrentToLast()
        {
            CurrentItem = SourceList.Last();
            return SourceList != null && SourceList.Count > 0;
        }

        public bool MoveCurrentToNext()
        {
            CurrentPosition++;
            if (CurrentPosition <= SourceList.Count)
            {
                CurrentItem = SourceList[CurrentPosition];
            }
            return CurrentPosition <= SourceList.Count;
        }

        public bool MoveCurrentToPosition(int position)
        {
            if (position <= SourceList.Count && position >= 0)
            {
                CurrentItem = SourceList[position];
            }
            return position <= SourceList.Count && position >= 0;
        }

        public bool MoveCurrentToPrevious()
        {
            CurrentPosition--;
            if (CurrentPosition <= SourceList.Count)
            {
                CurrentItem = SourceList[CurrentPosition];
            }
            return CurrentPosition <= SourceList.Count;
        }

        public void Refresh()
        {
        }
        private SortDescriptionCollection _sortDescriptions;
        public SortDescriptionCollection SortDescriptions
        {
            get
            {
                if (_sortDescriptions == null)
                {
                    _sortDescriptions = new SortDescriptionCollection();
                }
                return _sortDescriptions;
            }
        }

        private IList<TEntity> SourceList
        {
            get
            {
#if DEBUG
                if (SourceCollection != null)
                {
                    Debug.Assert(SourceCollection as IList<TEntity> != null, "Source Collection is null");
                }
#endif
                return SourceCollection as IList<TEntity> ?? new List<TEntity>();
            }
        }
        private IEnumerable _SourceCollection;
        public IEnumerable SourceCollection
        {
            get { return _SourceCollection; }
            set
            {
                if (value is QueryOperationResponse<TEntity>)
                {
                    _SourceCollection = ((QueryOperationResponse<TEntity>)value).ToList();
                    this.TotalItemCount = checked((int)((QueryOperationResponse<TEntity>)value).TotalCount);
                }
                else
                {
                    _SourceCollection = value;
                }
                RaiseCollectionChanged(NotifyCollectionChangedAction.Reset);
                RaisePropertyChanged("TotalItemCount");
                RaisePropertyChanged("SourceCollection");
            }
        }

        #endregion

        #region IEnumerable Members

        public System.Collections.IEnumerator GetEnumerator()
        {
            if (SourceCollection == null)
            {
                return Enumerable.Empty<TEntity>().GetEnumerator();
            }
            else
            {
                return SourceCollection.GetEnumerator();
            }
        }

        #endregion

        #region INotifyCollectionChanged Members

        public event System.Collections.Specialized.NotifyCollectionChangedEventHandler CollectionChanged;
        public void RaiseCollectionChanged(NotifyCollectionChangedAction action)
        {
            if (CollectionChanged != null)
            {
                CollectionChanged(this, new NotifyCollectionChangedEventArgs(action));
            }
        }

        #endregion





        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }

    internal class DeferRefreshHelper : IDisposable
    {
        public Action OnDispose { get; set; }
        #region IDisposable Members

        public void Dispose()
        {
            if (OnDispose != null)
            {
                OnDispose();
            }
        }

        #endregion
    }
}
